package com.generic.util;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;

public class GraphicsUtil {

	/**
	 * Convenience method that returns a scaled instance of the provided {@code
	 * BufferedImage}.
	 * 
	 * @param img the original image to be scaled
	 * @param targetWidth the desired width of the scaled instance, in pixels
	 * @param targetHeight the desired height of the scaled instance, in pixels
	 * @param hint one of the rendering hints that corresponds to {@code
	 *            RenderingHints.KEY_INTERPOLATION} (e.g. {@code
	 *            RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR}, {@code
	 *            RenderingHints.VALUE_INTERPOLATION_BILINEAR}, {@code
	 *            RenderingHints.VALUE_INTERPOLATION_BICUBIC})
	 * @param higherQuality if true, this method will use a multi-step scaling
	 *            technique that provides higher quality than the usual one-step
	 *            technique (only useful in downscaling cases, where {@code
	 *            targetWidth} or {@code targetHeight} is smaller than the
	 *            original dimensions, and generally only when the {@code
	 *            BILINEAR} hint is specified)
	 * @return a scaled version of the original {@code BufferedImage}
	 */
	public static BufferedImage getScaledInstance(BufferedImage img, int targetWidth, int targetHeight, Object hint, boolean higherQuality) {
		int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
		BufferedImage ret = (BufferedImage) img;
		int w, h;
		if (higherQuality) {
			// Use multi-step technique: start with original size, then
			// scale down in multiple passes with drawImage()
			// until the target size is reached
			w = img.getWidth();
			h = img.getHeight();
		} else {
			// Use one-step technique: scale directly from original
			// size to target size with a single drawImage() call
			w = targetWidth;
			h = targetHeight;
		}

		do {
			if (higherQuality && w > targetWidth) {
				w /= 2;
				if (w < targetWidth) {
					w = targetWidth;
				}
			}

			if (higherQuality && h > targetHeight) {
				h /= 2;
				if (h < targetHeight) {
					h = targetHeight;
				}
			}

			BufferedImage tmp = new BufferedImage(w, h, type);
			Graphics2D g2 = tmp.createGraphics();
			g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
			g2.drawImage(ret, 0, 0, w, h, null);
			g2.dispose();

			ret = tmp;
		} while (w != targetWidth || h != targetHeight);

		return ret;
	}

	public static BufferedImage getStandardSize(BufferedImage img) {
		int w = img.getWidth();
		int h = img.getHeight();
		int newW = w;
		int newH = h;
		boolean higherQuality = false;
		if(w > h) {
			if (w > Constant.IMAGE_MAX_WIDTH) {
				newW = Constant.IMAGE_MAX_WIDTH;
				newH = Constant.IMAGE_MAX_WIDTH * h / w;
				if(w > Constant.IMAGE_MAX_WIDTH * 2) {
					higherQuality = true;
				}
			}
		} else {
			if (h > Constant.IMAGE_MAX_HEIGHT) {
				newH = Constant.IMAGE_MAX_HEIGHT;
				newW = Constant.IMAGE_MAX_HEIGHT * w / h;
				if(h > Constant.IMAGE_MAX_HEIGHT * 2) {
					higherQuality = true;
				}
			}
		}		

		return getScaledInstance(img, newW, newH, RenderingHints.VALUE_INTERPOLATION_BILINEAR, higherQuality);
	}
	
	public static BufferedImage getThumbnailSize(BufferedImage img) {
		int w = img.getWidth();
		int h = img.getHeight();
		int newW = w;
		int newH = h;
		
		if (w > Constant.IMAGE_MIN_WIDTH) {
			newW = Constant.IMAGE_MIN_WIDTH;
			newH = Constant.IMAGE_MIN_WIDTH * h / w;
		}
		
		return getScaledInstance(img, newW, newH, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
	}
	
	public static BufferedImage getCoverSize(BufferedImage img) {
		if (img.getWidth() > Constant.IMAGE_PROFILE_WIDTH) {
			img = getScaledInstance(img, Constant.IMAGE_MIN_WIDTH, Constant.IMAGE_MIN_WIDTH, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
		}
		return img;
	}
}
